import Logger, { Level } from "./logger";
const logger = new Logger({
  color: "#ffffff",
  bgColor: "#1e90ff",
  prefix: "Dispatcher"
});
const scopeReg = /^([a-zA-Z][0-9a-zA-Z]*)+(\.[0-9a-zA-Z]+)*$/;
type VoidFuntion = (...args: any[]) => void | Promise<void>;
type BooleanFuntion = (...args: any[]) => boolean | Promise<boolean>;
export default class Dispatcher {
  static _map = new Map();
  static _level = "warn";
  /**
   * 设定日志等级
   * @param level
   */
  static level(level: Level) {
    logger.level(level);
  }
  /**
   * 注册
   * @param name 唯一id
   * @param exec
   * @param pre 前提条件，返回true则会执行exec
   */
  static register(
    name: string,
    exec: VoidFuntion,
    pre: BooleanFuntion = async () => true
  ): void {
    if (!name) {
      logger.error("name is required!");
      throw new Error("name is required!");
    }
    if (!scopeReg.test(name)) {
      logger.error(`"${name}" does not match pattern\n`, scopeReg);
      throw new Error("pattern not match");
    }
    if (Dispatcher._map.has(name)) {
      logger.error(`Duplicate name: ${name}`);
      throw new Error(`Duplicate name: ${name}`);
    }
    if (typeof exec !== "function") {
      logger.error(`exec should be exec: [async] () => void`);
      throw new Error(`exec should be exec: [async] () => void`);
    }
    if (typeof pre !== "function") {
      logger.error(`pre should be pre: [async] () => void`);
      throw new Error(`pre should be pre: [async] () => void`);
    }
    Dispatcher._map.set(name, { exec, pre });
    logger.log(`Registed ${name}`);
  }
  /**
   * 注销
   * @param name
   */
  static unregister(name: string): void {
    if (!Dispatcher._map.has(name)) {
      console.warn(`Action '${name}' not found.`);
      return;
    }
    Dispatcher._map.delete(name);
    logger.log(`Unregisted ${name}`);
  }
  /**
   * 分发
   * @param name
   * @returns true: 执行完毕, false: 被跳过
   */
  static async dispatch(name: string): Promise<boolean> {
    if (!Dispatcher._map.has(name)) {
      logger.error(`Action '${name}' not found.`);
      throw new Error(`Action '${name}' not found.`);
    }
    const { exec, pre } = Dispatcher._map.get(name);
    if ((await pre()) === false) return false;
    logger.log(`Dispatch ${name}`);
    await exec();
    return true;
  }
  /**
   * 销毁
   */
  static dispose(): void {
    Dispatcher._map.clear();
  }
}
